#include <stdio.h>
#include <string.h>

#include "cvmx-config.h"
#include "cvmx.h"
#include "cvmx-key.h"
#include "cvmx-swap.h"


/**
 * Calculate the MD5 hash of a block of data
 *
 * @param md5        Filled with the 16 byte MD5 hash
 * @param buffer     Input data
 * @param buffer_len Inout data length
 */
static void hash_md5(uint8_t *md5, const uint8_t *buffer, int buffer_len)
{
    const uint64_t bits = cvmx_cpu_to_le64(buffer_len * 8); /* MD5 expects little endian */
    const uint64_t *ptr = (const uint64_t *)buffer;
    uint8_t chunk[64];

    /* Set the IV to the MD5 magic start value */
    CVMX_MT_HSH_IV(0x0123456789abcdefull, 0);
    CVMX_MT_HSH_IV(0xfedcba9876543210ull, 1);

    /* MD5 input is in the following form:
        1) User data
        2) Byte 0x80
        3) Optional zero padding
        4) Original Data length in bits as an 8 byte unsigned integer
        Zero padding is added to make the 1-4 an even multiple of 64 bytes */

    /* Iterate through 64 bytes at a time */
    while (buffer_len >= 64)
    {
        CVMX_MT_HSH_DAT(*ptr++, 0);
        CVMX_MT_HSH_DAT(*ptr++, 1);
        CVMX_MT_HSH_DAT(*ptr++, 2);
        CVMX_MT_HSH_DAT(*ptr++, 3);
        CVMX_MT_HSH_DAT(*ptr++, 4);
        CVMX_MT_HSH_DAT(*ptr++, 5);
        CVMX_MT_HSH_DAT(*ptr++, 6);
        CVMX_MT_HSH_STARTMD5(*ptr++);
        buffer_len-=64;
    }

    /* The rest of the data will need to be copied into a chunk */
    if (buffer_len > 0)
        memcpy(chunk, ptr, buffer_len);
    chunk[buffer_len] = 0x80;
    memset(chunk + buffer_len + 1, 0, 64 - buffer_len - 1);

    ptr = (const uint64_t *)chunk;
    CVMX_MT_HSH_DAT(*ptr++, 0);
    CVMX_MT_HSH_DAT(*ptr++, 1);
    CVMX_MT_HSH_DAT(*ptr++, 2);
    CVMX_MT_HSH_DAT(*ptr++, 3);
    CVMX_MT_HSH_DAT(*ptr++, 4);
    CVMX_MT_HSH_DAT(*ptr++, 5);
    CVMX_MT_HSH_DAT(*ptr++, 6);

    /* Check to see if there is room for the bit count */
    if (buffer_len < 56)
        CVMX_MT_HSH_STARTMD5(bits);
    else
    {
        CVMX_MT_HSH_STARTMD5(*ptr);
        /* Another block was needed */
        CVMX_MT_HSH_DATZ(0);
        CVMX_MT_HSH_DATZ(1);
        CVMX_MT_HSH_DATZ(2);
        CVMX_MT_HSH_DATZ(3);
        CVMX_MT_HSH_DATZ(4);
        CVMX_MT_HSH_DATZ(5);
        CVMX_MT_HSH_DATZ(6);
        CVMX_MT_HSH_STARTMD5(bits);
    }

    /* Get the final MD5 */
    CVMX_MF_HSH_IV(((uint64_t*)md5)[0], 0);
    CVMX_MF_HSH_IV(((uint64_t*)md5)[1], 1);
}
static inline int strequ(char *str1,char *str2)
{
	int i=0;
	do{
		if(str1[i] == str2[i])
			continue;
		else
			return -1;
	}while(str1[i++] != '\0');
	return 0;
}

int main()
{
	uint8_t md5[128];
	char str[1024];
	int i;
	uint64_t start,end;

	start = cvmx_get_cycle();
	for(i = 0;i < 10000000;i++) 
		hash_md5((uint8_t *)md5,str,1024);
	end = cvmx_get_cycle();
	printf("1000w md5: %lu\n",end-start);

	start = cvmx_get_cycle();
	for(i = 0;i < 10000000;i++) 
		strequ(str,str);
	end = cvmx_get_cycle();
	printf("1000w strcmp: %lu\n",end-start);
	return 0;

}
